package com.sh.data.engine.common.util;

import cn.hutool.extra.spring.SpringUtil;
import lombok.Data;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.core.env.Environment;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author: mengzheng.mhc
 * @date: 2024/6/12 21:03
 */
public class RSAUtil {

    public static final String RSA_ALGORITHM = "RSA";
    public static final String UTF8 = "UTF-8";

    private static Environment environment = SpringUtil.getBean(Environment.class);

    //    private static Environment environment = null;

    /**
     * 创建公钥私钥
     *
     * @return
     * @throws Exception
     */
    public static KeyStore createKeys() throws Exception {
        KeyPairGenerator keyPairGeno = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        keyPairGeno.initialize(1024);
        KeyPair keyPair = keyPairGeno.generateKeyPair();

        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        KeyStore keyStore = new KeyStore();
        keyStore.setPublicKey(Base64.encodeBase64String(publicKey.getEncoded()));
        keyStore.setPrivateKey(Base64.encodeBase64String(privateKey.getEncoded()));
        return keyStore;
    }

    /**
     * 获取公钥对象
     *
     * @param pubKeyData
     * @return
     * @throws Exception
     */
    public static RSAPublicKey getPublicKey(byte[] pubKeyData) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyData);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        return (RSAPublicKey) keyFactory.generatePublic(keySpec);
    }

    /**
     * 获取公钥对象
     *
     * @param pubKey 公钥
     * @return
     * @throws Exception
     */
    public static RSAPublicKey getPublicKey(String pubKey) throws Exception {
        return getPublicKey(Base64.decodeBase64(pubKey));
    }

    /**
     * 获取私钥对象
     *
     * @param priKey 私钥
     * @return
     * @throws Exception
     */
    public static RSAPrivateKey getPrivateKey(String priKey) throws Exception {
        return getPrivateKey(Base64.decodeBase64(priKey));
    }

    /**
     * 通过私钥byte[]将公钥还原，适用于RSA算法
     *
     * @param keyBytes
     * @return
     * @throws Exception
     */
    public static RSAPrivateKey getPrivateKey(byte[] keyBytes) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    }

    public static String encryptByPublicKey(String data, String publicKey) throws Exception {
        return encryptByPublicKey(data, getPublicKey(publicKey));
    }

    public static String encryptByPublicKey(String data) throws Exception {
        return encryptByPublicKey(
            data, getPublicKey(environment.getProperty("encrypt.rsa.public.key")));
    }

    /**
     * 公钥加密
     *
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bytes = cipher.doFinal(data.getBytes(UTF8));
        return Base64.encodeBase64String(bytes);
    }

    public static String decryptByPublicKey(String data, String rsaPublicKey) throws Exception {
        return decryptByPublicKey(data, getPublicKey(rsaPublicKey));
    }

    /**
     * 公钥解密
     *
     * @param data
     * @param rsaPublicKey
     * @return
     * @throws Exception
     */
    public static String decryptByPublicKey(String data, RSAPublicKey rsaPublicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
        byte[] inputData = Base64.decodeBase64(data);
        byte[] bytes = cipher.doFinal(inputData);
        return new String(bytes, UTF8);
    }

    public static String encryptByPrivateKey(String data) throws Exception {
        return encryptByPrivateKey(data, environment.getProperty("encrypt.rsa.private.key"));
    }

    public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
        return encryptByPrivateKey(data, getPrivateKey(privateKey));
    }

    /**
     * 私钥加密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] bytes = cipher.doFinal(data.getBytes(UTF8));
        return Base64.encodeBase64String(bytes);
    }

    public static String decryptByPrivateKey(String data, String charset) throws Exception {
        return decryptByPrivateKey(
            data, getPrivateKey(environment.getProperty("encrypt.rsa.private.key")), charset);
    }

    public static String decryptByPrivateKey(String data, String privateKey, String charset)
        throws Exception {
        return decryptByPrivateKey(data, getPrivateKey(privateKey), charset);
    }

    /**
     * 私钥解密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
        return decryptByPrivateKey(data, privateKey, UTF8);
    }

    public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey, String charset)
        throws Exception {
        byte[] inputData = Base64.decodeBase64(data);

        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < inputData.length; i += 128) {
            byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(inputData, i, i + 128));
            sb.append(new String(doFinal, charset));
        }

        String outStr = sb.toString();

        return outStr;
    }

    @Data
    public static class KeyStore {
        private String publicKey;
        private String privateKey;
    }

    //  public static void main(String[] args) throws Exception {
    //    String publicKey =
    //
    // "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCAXJD28AM//5WszOA7UhWaZ/LzB8IB/cgqo+czTfp1znvCtHHOkrVzmPZArcE1AgafHWI7XBYopeTvopUkhtXcG4jN9zRcZldsO+v4TUryBe4mIfav1gBtHhX6V8l0gIo+9S/vh7h7hhxUN0vO14UL0k7ujhL+OXwgCcGLXh4jkwIDAQAB";
    //    String privateKey =
    //
    // "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIBckPbwAz//lazM4DtSFZpn8vMHwgH9yCqj5zNN+nXOe8K0cc6StXOY9kCtwTUCBp8dYjtcFiil5O+ilSSG1dwbiM33NFxmV2w76/hNSvIF7iYh9q/WAG0eFfpXyXSAij71L++HuHuGHFQ3S87XhQvSTu6OEv45fCAJwYteHiOTAgMBAAECgYA0IWPeZetr+mjXHP2UGeocI0tP2D66gE7iwl4LQAgQACPTF2WA96Qppl2cNvTYilIWHODgKq31JCquB+F6TCheAHayn0BSaB2ySUGiWZxhf66IdKqPz62WLHnduFaRPMVBnXt2lwnKHmUfPRo6oAqsw83MyDfTyxJJuBFpYVDggQJBAL/P0GRZANepwSHQXnkIYfDzM5vkAzVfjhg0OdpOxuOp6wm7jWbAl4nMPbE+cJNKs3r4jursGk3IhszWgX8RFAsCQQCrURVeqLYKtvSsMOFbnt5MEsyiqvwXYaRewRsI3U7cI/qixMC/oLMLyU0OnhtNLfzKMYK+bGk9lzx+wQMS5BuZAkEAsl5+W9KoheTGRLuQHt08tuRySbVvhmKlsLxgUDKRoYSRnStcAwF16h6UAA8ggNgmr2QVA0Er9MlVEYcoRRGMoQJAKGkY9Foxjrd3YYKqNfV0lFc+5AQXMOC8aAl++glSB8WI4oosuUcL1PTn81HCOONnJL6nC4oBDSE2iOO4eOVLyQJAIaf6E9s71FCCBypuq5St9PsB8sZnxJEXIUyTkR/rOyAUczFl2IPUuuLeyFUfGI0pGQuBt+qT7xlctlVnArsBWQ==";
    //    String data = "1234@Qwer中";
    //    String s = encryptByPublicKey(data, publicKey);
    //    System.out.println(s);
    //
    //    String encryValue =
    //
    // "VDKWt6CLFiJFYA0Xu/oVWpyMnZo9r5l6XY9aCw5fhMiKLFxXSWBc5BuGdfckv9GwqDMWj5xqG8+TKc/7IU/bew4NWCrZNKUrsCSXquylKAfbApnTJKN1IDVnfgnkJBEXyzddmLWOIgaQ7tnIFPLmEZ4fnIRIbjJtW0INCkY+l2Q=";
    //    String s1 = decryptByPrivateKey(encryValue, privateKey, "UTF-8");
    //
    //    System.out.println(s1);
    //  }
}
